import { GameLogic } from "../gameLogic/GameLogic"
import { EArea, EEntity, EStatus } from "../../shared/common/Enum"
import { IGameData, ITower } from "../../shared/common/Interface"
import { server } from "../.."
import { GameUser } from "./GameUser"
import { GameManager } from "./GameManager"
import { TowerLogic } from "../gameLogic/TowerLogic"
import { ExcelManager } from "./ExcelManager"
import { CMaxEnemyNum } from "../../shared/common/Contsant"
import { gameSpeed } from "../common/Contsant"
import { compressData } from "../common/Utils"

/** 游戏房间 */
export class GameRoom {

    intervalId: any
    /** 上一帧时间戳 */
    lastTime: number
    /** 游戏数据 */
    gameData: IGameData

    /** 卖出操作 */
    sellOperat: { userId: number, towerId: number }[] = []
    /** 抽卡操作 */
    drawOperat: { userId: number, entity: EEntity }[] = []
    /** 合成的删除操作 */
    mergeOperat: ITower[][] = []
    /** 待生成的塔 */
    generateTower: { area: EArea, entity: EEntity, roomId: number }[] = []

    /** 房间状态 */
    status: EStatus = EStatus.pause
    /** 房间里的用户 */
    users: GameUser[] = []

    /** 房间里的塔映射 */
    towers: { [key: number]: { [key: string]: ITower[] } } = {
        [EArea.up]: {},
        [EArea.down]: {},
    }

    constructor(roomId: number) {
        this.gameData = {} as any
        this.gameData.roomId = roomId
        this.reset()
        this.lastTime = new Date().getTime()
        this.intervalId = setInterval(() => { this.loop() }, 20)

    }

    private loop() {

        const curTime = new Date().getTime()
        this.gameData.step = (curTime - this.lastTime) / 1000 * gameSpeed
        this.lastTime = curTime

        /** 暂停中 */
        if (this.status == EStatus.pause) {
            return
        }

        /** 游戏失败 */
        if (this.status == EStatus.lost) {
            return
        }

        this.checkGameLost(this.gameData)
        
        GameLogic.Ins.gameBeforeLoop(this.gameData)
        GameLogic.Ins.gameMainLoop(this.gameData)
        GameLogic.Ins.gameLateLoop(this.gameData)

        TowerLogic.Ins.generateMWaitTower(this.generateTower)
        this.handleUserOperat(this.gameData)

        this.sendMsg()
    }

    /** 游戏数据默认值 */
    private reset() {

        this.gameData.nextId = 0
        this.gameData.step = 0
        this.gameData.users = []
        this.gameData.enemies = []
        this.gameData.towers = []
        this.gameData.levelData = {
            roundCountdown: 3,
            curRound: 0,
            difficulty: 0,
            numberlimit: CMaxEnemyNum,
        }
    }

    /** 向客户端同步消息 */
    async sendMsg() {
        const conns = [
            this.users[0].conn,
            this.users[1].conn,
        ] as any
        this.gameData.users = [this.users[0].data, this.users[1].data]

        const data = compressData(this.gameData)
        server.broadcastMsg('battle/SOutput', { data }, conns)
    }

    /** 用户进入 */
    userJoin(user: GameUser) {
        this.users.push(user)
        this.setRoomStatus()
    }

    /** 用户重联 */
    userRejoin() {
        this.setRoomStatus()
    }

    /** 用户断开连接 */
    disconn(userId: number) {
        const user = this.users.find(v => v.data.userId == userId)
        if (user) user.connStatus = EStatus.disconn
        this.setRoomStatus()
    }

    /** 设置房间状态 */
    setRoomStatus() {
        let connNum = 0
        for (const user of this.users) {
            if (user.connStatus == EStatus.conn) {
                ++connNum
            }
        }
        this.status = connNum == 2 ? EStatus.running : EStatus.pause
    }

    getNextId() {
        return ++this.gameData.nextId
    }

    /** 添加一个塔 */
    addTower(tower: ITower) {
        const { index, area } = tower
        this.gameData.towers.push(tower)
        if (this.towers[area]['' + index[0] + index[1]]) {
            this.towers[area]['' + index[0] + index[1]].push(tower)
        } else {
            this.towers[area]['' + index[0] + index[1]] = [tower]
        }
    }

    /** 卖出塔 */
    sellTower(userId: number, towerId: number) {
        this.sellOperat.push({ userId, towerId })
    }

    /** 抽取到塔 */
    drawTower(userId: number, entity: EEntity) {
        this.drawOperat.push({ userId, entity })
    }

    /** 合成塔 */
    mergeTower(area: EArea, indexX: number, indexY: number) {
        this.mergeOperat = []
        const towers = this.towers[area]['' + indexX + indexY]
        if (towers.length == 3) {
            ExcelManager.Ins.tableTower.init(towers[0].entityType)
            if (Number(ExcelManager.Ins.tableTower.quality) <= 4) {
                this.mergeOperat.push(towers)
            }
        }
    }

    /** 处理用户操作 */
    handleUserOperat(gameData: IGameData) {

        // 卖出塔
        if (this.sellOperat.length) {
            for (const { userId, towerId } of this.sellOperat) {
                const index = gameData.towers.findIndex(v => v.id == towerId)
                if (index >= 0) {
                    const user = GameManager.Ins.getUserById(userId)
                    gameData.towers[index].status = EStatus.dead
                    user.data.gold += 20
                }
            }
            this.sellOperat = []
        }

        // 塔抽卡
        this.generateTower = []
        if (this.drawOperat.length) {
            for (const { userId, entity } of this.drawOperat) {
                const user = GameManager.Ins.getUserById(userId)
                this.generateTower.push({ area: user.data.area, entity, roomId: this.gameData.roomId })
            }
            this.drawOperat = []
        }

        // 合成塔
        if (this.mergeOperat.length) {
            for (const towerArr of this.mergeOperat) {
                let entityType = EEntity.tower1
                let area = EArea.down
                for (const tower of towerArr) {
                    tower.status = EStatus.dead
                    entityType = tower.entityType
                    area = tower.area
                }
                entityType = TowerLogic.Ins.getMergeTowerType(entityType)
                this.generateTower.push({ area, entity: entityType, roomId: this.gameData.roomId })
            }
            this.mergeOperat = []
        }
    }

    /** 移除塔的映射 */
    removeTower2map(area: EArea, index: [number, number], id: number) {
        const towerArr = this.towers[area]['' + index[0] + index[1]]
        const towerIndex = towerArr.findIndex(v => v.id == id)
        if (towerIndex > -1) {
            towerArr.splice(towerIndex, 1)
        }
    }

    /** 游戏失败检测 */
    checkGameLost(gameData: IGameData) {
        if (gameData.enemies.length >= gameData.levelData.numberlimit) {
            this.status = EStatus.lost
            clearInterval(this.intervalId)
        }
        
    }

    /** 防御塔换位置 */
    exchangePos(index1: number, index2: number, area: EArea) {

        if (!this.towers[area][index1] && !this.towers[area][index2]) {// 没有塔
            return
        }

        const indexA1 = Math.floor(index1 / 10)
        const indexA2 = Math.floor(index1 % 10)

        const indexB1 = Math.floor(index2 / 10)
        const indexB2 = Math.floor(index2 % 10)

        const towerAs = this.gameData.towers.filter(v => v.index[0] == indexA1 && v.index[1] == indexA2 && v.area == area)
        const towerBs = this.gameData.towers.filter(v => v.index[0] == indexB1 && v.index[1] == indexB2 && v.area == area)

        if (towerAs.length) {
            for (const towerA of towerAs) {
                towerA.index = [indexB1, indexB2]
                const { x, y } = TowerLogic.Ins.getTowerPos(area, towerA.index)
                towerA.x = x
                towerA.y = y
            }
        }

        if (towerBs.length) {
            for (const towerB of towerBs) {
                towerB.index = [indexA1, indexA2]
                const { x, y } = TowerLogic.Ins.getTowerPos(area, towerB.index)
                towerB.x = x
                towerB.y = y
            }
        }

        let temp = this.towers[area][index1]
        this.towers[area][index1] = this.towers[area][index2]
        this.towers[area][index2] = temp

    }
}